import tkinter as tk  
from tkinter import filedialog, simpledialog, messagebox, Checkbutton  
import subprocess  
import os  
  
class APKSignerApp:  
    def __init__(self, root):  
        self.root = root  
        self.root.title("APK 签名工具")  
  
        # 初始化变量  
        self.apk_path = tk.StringVar()  
        self.jks_path = tk.StringVar()  
        self.alias = tk.StringVar()  
        self.password = tk.StringVar()  
        self.build_tools_path = tk.StringVar()  
        self.zipalign_checked = tk.BooleanVar(value=True)  # 默认勾选对齐  
  
        # 创建GUI组件  
        self.create_widgets()  
  
    def create_widgets(self):  
        # APK文件路径  
        tk.Label(self.root, text="APK文件路径:").pack()  
        tk.Entry(self.root, textvariable=self.apk_path, width=70).pack()  
        tk.Button(self.root, text="选择APK文件", command=self.select_apk_file).pack(pady=5)  
  
        # 密钥库文件路径  
        tk.Label(self.root, text="密钥库文件(.jks)路径:").pack()  
        tk.Entry(self.root, textvariable=self.jks_path, width=70).pack()  
        tk.Button(self.root, text="选择密钥库文件", command=self.select_jks_file).pack(pady=5)  
  
        # 别名  
        tk.Label(self.root, text="alias别名:").pack()  
        tk.Entry(self.root, textvariable=self.alias, width=30).pack()  
  
        # 密码  
        tk.Label(self.root, text="签名密码:").pack()  
        tk.Entry(self.root, textvariable=self.password, show="*", width=30).pack()  
  
        # Build Tools路径  
        tk.Label(self.root, text="Build Tools路径:").pack()  
        tk.Entry(self.root, textvariable=self.build_tools_path, width=70).pack()  
        tk.Button(self.root, text="选择Build Tools路径", command=self.select_build_tools_path).pack(pady=5)  
  
        # 是否进行APK对齐  
        Checkbutton(self.root, text="对齐APK", variable=self.zipalign_checked).pack(pady=5)  
  
        # 签名按钮  
        tk.Button(self.root, text="签名APK", command=self.sign_apk).pack(pady=20)  
  
    def select_apk_file(self):  
        self.apk_path.set(filedialog.askopenfilename(filetypes=[("APK files", "*.apk")]))  
  
    def select_jks_file(self):  
        self.jks_path.set(filedialog.askopenfilename(filetypes=[("JKS files", "*.jks")]))  
  
    def select_build_tools_path(self):  
        self.build_tools_path.set(filedialog.askdirectory(title="选择Build Tools目录"))  
  
    def sign_apk(self):  
        if not self.apk_path.get() or not self.jks_path.get() or not self.alias.get() or not self.password.get() or not self.build_tools_path.get():  
          messagebox.showerror("错误", "请完整填写所有必要信息！")  
          return   
  
        # 获取未签名APK的目录  
        apk_dir = os.path.dirname(self.apk_path.get())  
        # 设置输出APK的路径为与未签名APK相同的目录，但文件名不同  
        output_apk = os.path.join(apk_dir, "signed_" + os.path.basename(self.apk_path.get()))  
  
        # 获取 Build Tools 下的 apksigner 和 zipalign 路径  
        apksigner_path = os.path.join(self.build_tools_path.get(), "apksigner.bat")  # 注意：Windows 上可能是 .bat 文件  
        zipalign_path = os.path.join(self.build_tools_path.get(), "zipalign.exe")  # 确保使用 .exe 扩展名    
            
        # 打印路径以进行调试  
        print("apksigner_path:", apksigner_path)  
        print("zipalign_path:", zipalign_path)  
  
        # 如果勾选了对齐  
        if self.zipalign_checked.get():  
            try:  
                # zipalign 命令  
                subprocess.run([zipalign_path, "-p", "-f", "-v", "4", self.apk_path.get(), output_apk + ".unaligned"], check=True)  
                # apksigner 命令  
                subprocess.run([apksigner_path, "sign", "--ks", self.jks_path.get(), "--ks-key-alias", self.alias.get(),  
                                "--ks-pass", f"pass:{self.password.get()}",  
                                "--out", output_apk, output_apk + ".unaligned"], check=True)  
                # 删除未对齐的临时文件  
                os.remove(output_apk + ".unaligned")  
                messagebox.showinfo("成功", "APK 签名并对齐成功！已保存到：{}".format(output_apk))  
            except subprocess.CalledProcessError as e:  
                messagebox.showerror("错误", f"处理APK时出错：{e}")  
        else:  
            # 如果没有勾选对齐，则直接签名  
            try:  
                subprocess.run([apksigner_path, "sign", "--ks", self.jks_path.get(), "--ks-key-alias", self.alias.get(),  
                                "--ks-pass", f"pass:{self.password.get()}",  
                                "--out", output_apk, self.apk_path.get()], check=True)  
                messagebox.showinfo("成功", "APK 签名成功！已保存到：{}".format(output_apk))  
            except subprocess.CalledProcessError as e:  
                messagebox.showerror("错误", f"签名APK时出错：{e}")  
  
if __name__ == "__main__":  
    root = tk.Tk()  
    app = APKSignerApp(root)  
    root.mainloop()